<!DOCTYPE HTML>
<html>
<head>
  <title>Web database storage</title>
  <script src='../test_bootstrap.js'></script>
  <script type='text/javascript'>
    goog.require('bot');
    goog.require('bot.html5');
    goog.require('bot.storage.database');
    goog.require('goog.testing.AsyncTestCase');
    goog.require('goog.testing.jsunit');
  </script>

  <script type='text/javascript'>
    var asyncTestCase = null;

    /**
     * Initial function to create the database. I use the top-level window
     * to create the database.
     * This function must not fail or throw error for of the test functions.
     */
    function setUpPage() {
      if (!bot.html5.isSupported(bot.html5.API.DATABASE)) {
        return;
      }

      try {
        var win = bot.getWindow();
        var db = win.openDatabase('testDB', '1.0', 'db name', 5*1024*1024);
        db.transaction(transactionCallback, errorCallback, successCallback);
        asyncTestCase.waitForAsync('testExecuteSqlWithSelectAll');
      } catch (e) {
        throw new bot.Error(bot.ErrorCode.UNKNOWN_ERROR, e.message);
      }

      function errorCallback(error) {
        throw new bot.Error(bot.ErrorCode.UNKNOWN_ERROR, error.message);
      }

      function successCallback(error) {
        asyncTestCase.continueTesting();
      }

      function transactionCallback(tx) {
        tx.executeSql('CREATE TABLE IF NOT EXISTS docids (id INTEGER \
            PRIMARY KEY, name TEXT, owner TEXT)');
        tx.executeSql('INSERT OR REPLACE INTO docids VALUES (11, "aa", "Manager")');
        tx.executeSql('INSERT OR REPLACE INTO docids VALUES (1, "aabb", "Eng-A")');
        tx.executeSql('INSERT OR REPLACE INTO docids VALUES (31, "abc", "Eng-B")');
        tx.executeSql('INSERT OR REPLACE INTO docids VALUES (0, "aabb", "Eng-A")');
        tx.executeSql('INSERT OR REPLACE INTO docids VALUES (2, "yyy", "Eng-D")');
        tx.executeSql('INSERT OR REPLACE INTO docids VALUES (3, "zzz", "Eng-A")');
        tx.executeSql('INSERT OR REPLACE INTO docids VALUES (90, "aabb", "Eng-E")');
      }
    }


    function testOpenDatabaseWithSameVersion() {
      if (!bot.html5.isSupported(bot.html5.API.DATABASE)) {
        return;
      }

      var db;
      try {
        db = bot.storage.database.openOrCreate('testDB', '1.0');
      } catch (e) {
        fail(e.message);
      }

      assertNotNull(db);
      assertEquals(db.version, '1.0');
    }


    function testOpenDatabaseWithAnyVersion() {
      if (!bot.html5.isSupported(bot.html5.API.DATABASE)) {
        return;
      }

      var db;
      try {
        db = bot.storage.database.openOrCreate('testDB');
      } catch (e) {
        fail(e.message);
      }

      assertNotNull(db);
      assertEquals(db.version, '1.0');
    }


    function testOpenDatabaseWrongVersion() {
      if (!bot.html5.isSupported(bot.html5.API.DATABASE)) {
        return;
      }

      try {
        var db = bot.storage.database.open('testDB', '2.0');
      } catch (e) {
        // Exception should be thrown on opening a database with wrong
        // version.
        return;
      }

      fail('Database should fail to open.');
    }


    function testExecuteSqlWithInvalidSqlStatement() {
      if (!bot.html5.isSupported(bot.html5.API.DATABASE)) {
        return;
      }

      try {
        // WITH is errorneously used instead of WHERE
        bot.storage.database.executeSql('testDB',
            'SELECT * from docids WITH id = 1', [], queryResultCallback,
            txErrorCallback, txSuccessCallback);
      } catch (e) {
        var errMsg = 'No exception should be raised on opening the database; ' +
                'otherwise be handled by callback';
        fail(errMsg);
        return;
      }

      asyncTestCase.waitForAsync('testExecuteSqlWithInvalidSqlStatement');

      function queryResultCallback(tx, result) {
        //assertEquals(result.rows.length, 1);
        fail('Transaction should not succeed with invalid SQL statement');
      }

      function txErrorCallback(error) {
        asyncTestCase.continueTesting();
      }

      function txSuccessCallback() {
        asyncTestCase.continueTesting();
        fail('Transaction should not succeed with invalid SQL statement');
      }
    }


    function testExecuteSqlWithValidArgument() {
      if (!bot.html5.isSupported(bot.html5.API.DATABASE)) {
        return;
      }

      try {
        bot.storage.database.executeSql('testDB',
            'SELECT id from docids WHERE owner = ? AND name = ?',
            ['Eng-A', 'aabb'], queryResultCallback, txErrorCallback,
            txSuccessCallback);
      } catch (e) {
        var errMsg = 'No exception should be raised on opening the database; ' +
                        'otherwise it must be handled by callback';
        fail(errMsg);
        return;
      }

      asyncTestCase.waitForAsync('testExecuteSqlWithInvalidSqlStatement');

      function queryResultCallback(tx, result) {
        assertEquals(result.rows.length, 2);
        assertEquals(result.rowsAffected, 0);
        assertEquals(result.rows[0].id, 0);
        assertEquals(result.rows[1].id, 1);
      }

      function txErrorCallback(error) {
        asyncTestCase.continueTesting();
        fail('Transaction should succeed, not fail');
      }

      function txSuccessCallback() {
        asyncTestCase.continueTesting();
      }
    }


    function testExecuteSqlInsertAndDelete() {
      if (!bot.html5.isSupported(bot.html5.API.DATABASE)) {
        return;
      }

      //Grouping insert and delete together to keep no side-effect later.
      executeSqlInsert();
      executeSqlDelete();
    }

    function executeSqlInsert() {
      try {
        bot.storage.database.executeSql('testDB',
            'INSERT OR REPLACE INTO docids (id, name, owner) VALUES (?, ?, ?)',
            [999, 'file1', 'Eng-L'], queryResultCallback, txErrorCallback,
            txSuccessCallback);
      } catch (e) {
        var errMsg = 'No exception should be raised on opening the database; ' +
                        'otherwise it must be handled by callback';
        fail(errMsg);
        return;
      }

      asyncTestCase.waitForAsync('testExecuteSqlInsert');

      function queryResultCallback(tx, result) {
        assertEquals(result.rowsAffected, 1);
        assertEquals(result.rows.length, 0);
      }

      function txErrorCallback(error) {
        asyncTestCase.continueTesting();
        fail('Transaction should succeed, not fail');
      }

      function txSuccessCallback() {
        asyncTestCase.continueTesting();
      }
    }

    function executeSqlDelete() {
      try {
        bot.storage.database.executeSql('testDB',
            'DELETE FROM docids WHERE id=999',
            [], queryResultCallback, txErrorCallback,
            txSuccessCallback);
      } catch (e) {
        var errMsg = 'No exception should be raised on opening the database; ' +
                        'otherwise it must be handled by callback';
        fail(errMsg);
        return;
      }

      asyncTestCase.waitForAsync('testExecuteSqlInsert');

      function queryResultCallback(tx, result) {
        assertEquals(result.rowsAffected, 1);
        assertEquals(result.rows.length, 0);
      }

      function txErrorCallback(error) {
        asyncTestCase.continueTesting();
        fail('Transaction should succeed, not fail');
      }

      function txSuccessCallback() {
        asyncTestCase.continueTesting();
      }
    }
  </script>
</head>
<body>
<script type="text/javascript">
  asyncTestCase = goog.testing.AsyncTestCase.createAndInstall();
  asyncTestCase.stepTimeout = 15 * 1000;
</script>
</body>
</html>
